
message Deploy {
    queryId: Int as uint64;
    inWallet: Address;
    outWallet: Address;
}

message DeployOk {
    queryId: Int as uint64;
}

message(0xd53276db) Excesses {
    queryId: Int as uint64;
}

message(0x0f8a7ea5) JettonTransfer {
    query_id: Int as uint64; // arbitrary request number
    amount: Int as coins; // amount of jettons to transfer
    destination: Address; // address of the new owner of the jettons
    response_destination: Address; // address where to send a response with confirmation of a successful transfer and the rest of the incoming message Toncoins.
    custom_payload: Cell?; // optional custom payload
    forward_ton_amount: Int as coins; // the amount of nanotons to be sent to the destination address.
    forward_payload: Slice as remaining; // optional custom data that should be sent to the destination address.
}

message(0x7362d09c) JettonTransferNotification {
    query_id: Int as uint64;
    amount: Int as coins;
    sender: Address;
    forward_payload: Slice as remaining;
}

message Withdraw {
    query_id: Int as uint64;
    inAmount: Int as coins;
    outAmount: Int as coins;
}

struct JettonWalletData {
    balance: Int as coins;
    ownerAddress: Address;
    jettonMasterAddress: Address;
    jettonWalletCode: Cell;
}

fun calculateJettonWalletAddress(ownerAddress: Address, jettonMasterAddress: Address, jettonWalletCode: Cell): Address {
    let initData = JettonWalletData{
        balance: 0,
        ownerAddress,
        jettonMasterAddress,
        jettonWalletCode,
    };

    return contractAddress(StateInit{code: jettonWalletCode, data: initData.toCell()});
}

contract MySwap {
    owner: Address;
    inWallet: Address?;
    outWallet: Address?;
    // 100000个nano in换 price 个nano out
    price: Int as coins;
    inReverse: Int as coins = 0;
    outReverse: Int as coins = 0;

    init(owner: Address, price: Int) {
        self.owner = owner;
        self.price = price;
        self.inWallet = null;
        self.outWallet = null;
    }
    
    receive(msg: Deploy) {
        self.inWallet = msg.inWallet;
        self.outWallet = msg.outWallet;
        self.notify(DeployOk{queryId: msg.queryId}.toCell());
    }
    
    // 接收退款
    receive(msg: Excesses) {
    }
    
    // 此时jetton已经成功发送到本合约的钱包上
    receive(msg: JettonTransferNotification){
        let ctx: Context = context();
        let ctx_sender: Address = ctx.sender;
        // 接收in代币,in代币只进不出,后续通过提现统一提出 out代币
        if(ctx_sender == self.inWallet) {
            self.inReverse += msg.amount;
            return;
        }
        // 接收out代币,根据价格换出 in代币.
        // 支持usdt与普通代币的转换,需要有3位精度差, 因此从 100*1000, 再增加3位, 到 100*1000*1000;
        if(ctx_sender == self.outWallet) {
            // 如果in代币的储备不足,不退回out代币
            self.outReverse += msg.amount;
            commit();
            let in_amount = msg.amount * self.price / 100_000_000;
            // 储备不足
            nativeThrowIf(413, self.inReverse < in_amount );
            self.inReverse -= in_amount;
            // 换出 in 币
            self.send_simple_jettons(msg.query_id, 0, in_amount, msg.sender, self.inWallet!!);
            return;
        }
        // 不支持代币
        nativeThrowIf(1003, true);
        return;
    }

    // 一个方法里同时发多笔交易时,需要确保每笔交易都有足够的ton消费.
    // SendRemainingValue 模式会将多余的ton一起发走,导致其他交易没有足够的ton
    receive(msg: Withdraw){
        let ctx: Context = context();
        let value = ctx.value / 2;
        // 至少0.01个币才能提取
        if(msg.outAmount >= 10_000_000){
            self.send_simple_jettons(msg.query_id, value, msg.outAmount, ctx.sender, self.outWallet!!);
            if(msg.outAmount>=self.outReverse){
                self.outReverse = 0;
            }else{
                self.outReverse -= msg.outAmount;
            }
        }
        // usdt 精度为6
        if(msg.inAmount >= 10_000){
            self.send_simple_jettons(msg.query_id, value, msg.inAmount, ctx.sender, self.inWallet!!);
            if(msg.inAmount>=self.inReverse){
                self.inReverse = 0;
            }else{
                self.inReverse -= msg.inAmount;
            }
        }
        return;
    }
    
    fun send_simple_jettons(query_id: Int, msg_value: Int, jetton_amount: Int, destination: Address, jetton_address: Address) {
        let forward_payload = beginCell().storeUint(0, 1).endCell().beginParse();
        send(SendParameters{
            to: jetton_address,
            value: msg_value,
            bounce: false,
            mode: SendRemainingValue,
            body: JettonTransfer {
                query_id: query_id,
                amount: jetton_amount,
                destination: destination,
                response_destination: myAddress(),
                custom_payload: emptyCell(),
                forward_ton_amount: 0,
                forward_payload: forward_payload,
 
            }.toCell()
        });
    }
    
    get fun price(): Int {
        return self.price;
    }
    get fun inReverse(): Int {
        return self.inReverse;
    }
    get fun outReverse(): Int {
        return self.outReverse;
    }
}
